package org.fuxia.im.db.dao.base.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.fuxia.im.db.dao.base.GenericDAO;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * 所有DAO的抽象基类，实现基本的增删查改功能。只作被继承用，不可被实例化。
 * 
 * @param <T>实体类
 * 
 * @param <PK>主键类
 */
public abstract class GenericDAOImpl<T, PK extends Serializable> extends HibernateDaoSupport implements
		GenericDAO<T, PK>
{

	
	private Class<T>	entityClass;

	// 将sessionFactory注入父类HibernateDaoSupport的hibernateTemplate
	@Autowired
	public void setSessionFactoryOverride(SessionFactory sessionFactory)
	{
		super.setSessionFactory(sessionFactory);
	}

	// -------------------- 基本检索、增加、修改、删除操作 --------------------

	/**
	 * 根据主键获取实体。如果没有相应的实体，返回 null。
	 */
	public T getByPK(PK id)
	{
		
		return (T) getHibernateTemplate().get(getEntityClass(), id);
	}

	/**
	 * 根据主键获取实体并加锁。如果没有相应的实体，返回 null。
	 */
	public T getByPKWithLock(PK id , LockMode lockMode)
	{
		return (T) getHibernateTemplate().get(getEntityClass(), id, lockMode);
	}

	/**
	 * 根据主键获取实体。如果没有相应的实体，抛出异常。
	 */
	public T loadByPK(PK id)
	{
		return (T) getHibernateTemplate().load(getEntityClass(), id);
	}

	/**
	 * 获取全部实体。
	 */
	public List<T> loadAll()
	{
		return (List<T>) getHibernateTemplate().loadAll(getEntityClass());
	}

	/**
	 * 更新实体
	 */
	public void update(T entity)
	{
		getHibernateTemplate().update(entity);
	}

	/**
	 * 存储实体到数据库
	 */
	public PK save(T entity)
	{
		PK pk =  (PK)getHibernateTemplate().save(entity);
		getHibernateTemplate().getSessionFactory().evict(getEntityClass(), pk);
		return pk ;
	}

	/**
	 * 存储实体到数据库
	 */
	public void saveOrUpdate(T entity)
	{
		getHibernateTemplate().saveOrUpdate(entity);
	}

	/**
	 * 增加或更新集合中的全部实体
	 */
	public void saveOrUpdateAll(Collection<T> entities)
	{
		getHibernateTemplate().saveOrUpdateAll(entities);
	}

	public T merge(T entity)
	{
		return getHibernateTemplate().merge(entity);
	}

	/**
	 * 删除指定的实体
	 */
	public void delete(T entity)
	{
		getHibernateTemplate().delete(entity);
	}

	/**
	 * 根据主键删除指定实体
	 */
	public void deleteByPK(PK id)
	{
		this.delete(this.loadByPK(id));
	}

	/**
	 * 删除集合中的全部实体
	 */
	public void deleteAll(Collection<T> entities)
	{
		getHibernateTemplate().deleteAll(entities);
	}

	// -------------------- HSQL ----------------------------------------------

	/**
	 * 使用HSQL语句直接增加、更新、删除实体
	 */
	public int bulkUpdate(String queryString)
	{
		return getHibernateTemplate().bulkUpdate(queryString);
	}

	/**
	 * 使用带参数的HSQL语句增加、更新、删除实体
	 */
	public int bulkUpdate(String queryString , Object[] values)
	{
		return getHibernateTemplate().bulkUpdate(queryString, values);
	}

	/**
	 * 使用HSQL语句检索数据
	 */
	@SuppressWarnings("unchecked")
	public List find(String queryString)
	{
		return getHibernateTemplate().find(queryString);
	}

	/**
	 * 使用带参数的HSQL语句检索数据
	 */
	public List find(String queryString , Object[] values)
	{
		return getHibernateTemplate().find(queryString, values);
	}

	/**
	 * 使用带命名的参数的HSQL语句检索数据
	 */
	public List findByNamedParam(String queryString , String[] paramNames , Object[] values)
	{
		return getHibernateTemplate().findByNamedParam(queryString, paramNames, values);
	}

	/**
	 * 使用命名的HSQL语句检索数据
	 */
	public List findByNamedQuery(String queryName)
	{
		return getHibernateTemplate().findByNamedQuery(queryName);
	}

	/**
	 * 使用带参数的命名HSQL语句检索数据
	 */
	public List findByNamedQuery(String queryName , Object[] values)
	{
		return getHibernateTemplate().findByNamedQuery(queryName, values);
	}

	/**
	 * 使用带命名参数的命名HSQL语句检索数据
	 */
	public List findByNamedQueryAndNamedParam(String queryName , String[] paramNames , Object[] values)
	{
		return getHibernateTemplate().findByNamedQueryAndNamedParam(queryName, paramNames, values);
	}

	/**
	 * 使用HSQL语句检索数据，返回 Iterator
	 */
	public Iterator iterate(String queryString)
	{
		return getHibernateTemplate().iterate(queryString);
	}

	/**
	 * 使用带参数HSQL语句检索数据，返回 Iterator
	 */
	@SuppressWarnings("unchecked")
	public Iterator<T> iterate(String queryString , Object[] values)
	{
		return getHibernateTemplate().iterate(queryString, values);
	}

	/**
	 * 关闭检索返回的 Iterator
	 */
	public void closeIterator(Iterator<?> it)
	{
		getHibernateTemplate().closeIterator(it);
	}

	// -------------------------------- Criteria ------------------------------

	/**
	 * 创建与会话无关的检索标准
	 */
	public DetachedCriteria createDetachedCriteria()
	{
		return DetachedCriteria.forClass(this.getEntityClass());
	}

	/**
	 * 创建与会话绑定的检索标准
	 */
	public Criteria createCriteria()
	{
		return this.createDetachedCriteria().getExecutableCriteria(this.getSession());
	}

	/**
	 * 检索满足标准的数据
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(DetachedCriteria criteria)
	{
		return getHibernateTemplate().findByCriteria(criteria);
	}

	/**
	 * 检索满足标准的数据，返回指定范围的记录
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(DetachedCriteria criteria , int firstResult , int maxResults)
	{
		return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
	}

	/**
	 * 使用指定的实体及属性检索（满足除主键外属性＝实体值）数据
	 */
	@SuppressWarnings("unchecked")
	public List<T> findEqualByEntity(T entity , String[] propertyNames)
	{
		Criteria criteria = this.createCriteria();
		Example exam = Example.create(entity);
		exam.excludeZeroes();
		String[] defPropertys = getSessionFactory().getClassMetadata(getEntityClass()).getPropertyNames();
		for (String defProperty : defPropertys)
		{
			int ii = 0;
			for (ii = 0; ii < propertyNames.length; ++ii)
			{
				if (defProperty.equals(propertyNames[ii]))
				{
					criteria.addOrder(Order.asc(defProperty));
					break;
				}
			}
			if (ii == propertyNames.length)
			{
				exam.excludeProperty(defProperty);
			}
		}
		criteria.add(exam);
		return (List<T>) criteria.list();
	}

	/**
	 * 使用指定的检索标准获取满足标准的记录数
	 */
	public Integer getRowCount(DetachedCriteria criteria)
	{
		criteria.setProjection(Projections.rowCount());
		List<T> list = this.findByCriteria(criteria, 0, 1);
		return (Integer) list.get(0);
	}

	// -------------------------------- Others --------------------------------

	/**
	 * 加锁指定的实体
	 */
	public void lock(T entity , LockMode lock)
	{
		getHibernateTemplate().lock(entity, lock);
	}

	/**
	 * 强制初始化指定的实体
	 */
	public void initialize(Object proxy)
	{
		getHibernateTemplate().initialize(proxy);
	}

	/**
	 * 强制立即更新缓冲数据到数据库（否则仅在事务提交时才更新）
	 */
	public void flush()
	{
		getHibernateTemplate().flush();
	}

	/**
	 * 获取指定范围的全部实体
	 */
	@SuppressWarnings("unchecked")
	public List<T> findAll(final int firstResult , final int maxResults)
	{
		//		return findByCriteria(createDetachedCriteria().setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY), firstResult, maxResults);
		return getHibernateTemplate().executeFind(new HibernateCallback<List<T>>() {
			public List<T> doInHibernate(Session session) throws HibernateException , SQLException
			{
				Query query = session.createQuery("select o from " + getEntityClass().getName() + " o");
				query.setFirstResult(firstResult);
				query.setMaxResults(maxResults);
				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<T> executeFind(HibernateCallback<?> action)
	{
		return this.getHibernateTemplate().executeFind(action);
	}

	/**
	 * 获取当前DAO对应的实体类
	 */
	@SuppressWarnings("unchecked")
	public Class<T> getEntityClass()
	{

		if (this.entityClass == null)
		{
			//遍历clazz到GenericDAOImpl的直接子类
			Class<?> clazz = getClass();
			while (!clazz.getSuperclass().getSimpleName().equals("GenericDAOImpl"))
			{
				clazz = clazz.getSuperclass();
			}
			// 通过反射获取GenericDAOImpl的直接子类在继承GenericDAOImpl是用到的泛型T所代表的类
			this.entityClass = (Class<T>) ((ParameterizedType) (clazz.getGenericSuperclass())).getActualTypeArguments()[0];
		}
		return entityClass;
	}

}
